﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using l1cs.server.model.Instance;
using l1cs.server.templates;
using l1cs.server.utils;
using MySql.Data.MySqlClient;

namespace l1cs.server.datatables
{
    public class PetTable
    {
        private static Logger _log = Logger.getLogger( typeof( PetTable ).FullName );

        private static PetTable _instance;

        private Dictionary<int, L1Pet> _pets = new Dictionary<int, L1Pet>();

        public static PetTable getInstance()
        {
            if ( _instance == null )
            {
                _instance = new PetTable();
            }
            return _instance;
        }

        private PetTable()
        {/*TTOK*/ 
            String sqlstr = "SELECT * FROM pets";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                foreach ( DataRow item in wrapper.GetDataTable( sqlstr ).Rows )
                {
                    L1Pet pet = new L1Pet();
                    int itemobjid = SqlUtils.toInt( item["item_obj_id"] );
                    pet.set_itemobjid( itemobjid );
                    pet.set_objid( SqlUtils.toInt( item["objid"] ) );
                    pet.set_npcid( SqlUtils.toInt( item["npcid"] ) );
                    pet.set_name( Convert.ToString( item["name"] ) );
                    pet.set_level( SqlUtils.toInt( item["lvl"] ) );
                    pet.set_hp( SqlUtils.toInt( item["hp"] ) );
                    pet.set_mp( SqlUtils.toInt( item["mp"] ) );
                    pet.set_exp( SqlUtils.toInt( item["exp"] ) );
                    pet.set_lawful( SqlUtils.toInt( item["lawful"] ) );

                    _pets[itemobjid] = pet;
                }
            }
        }

        public void storeNewPet( L1NpcInstance pet, int objid, int itemobjid )
        {/*TTOK*/
            // XXX 呼ばれる前と処理の重複
            L1Pet l1pet = new L1Pet();
            l1pet.set_itemobjid( itemobjid );
            l1pet.set_objid( objid );
            l1pet.set_npcid( pet.getNpcTemplate().get_npcId() );
            l1pet.set_name( pet.getNpcTemplate().get_name() );
            l1pet.set_level( pet.getNpcTemplate().get_level() );
            l1pet.set_hp( pet.getMaxHp() );
            l1pet.set_mp( pet.getMaxMp() );
            l1pet.set_exp( 750 ); // Lv.5のEXP
            l1pet.set_lawful( 0 );
            _pets[itemobjid] = l1pet;

            String sqlstr = @"INSERT INTO pets SET 
                                item_obj_id = ?1, 
                                objid       = ?2,
                                npcid       = ?3, 
                                name        = ?4, 
                                lvl         = ?5, 
                                hp          = ?6, 
                                mp          = ?7, 
                                exp         = ?8, 
                                lawful      = ?9";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = l1pet.get_itemobjid();
                cmd.Parameters.Add( "?2", MySqlDbType.Int32 ).Value = l1pet.get_objid();
                cmd.Parameters.Add( "?3", MySqlDbType.Int32 ).Value = l1pet.get_npcid();
                cmd.Parameters.Add( "?4", MySqlDbType.String ).Value = l1pet.get_name();
                cmd.Parameters.Add( "?5", MySqlDbType.Int32 ).Value = l1pet.get_level();
                cmd.Parameters.Add( "?6", MySqlDbType.Int32 ).Value = l1pet.get_hp();
                cmd.Parameters.Add( "?7", MySqlDbType.Int32 ).Value = l1pet.get_mp();
                cmd.Parameters.Add( "?8", MySqlDbType.Int32 ).Value = l1pet.get_exp();
                cmd.Parameters.Add( "?9", MySqlDbType.Int32 ).Value = l1pet.get_lawful();

                wrapper.ExecNonQuery( cmd );
            }
        }

        public void storePet( L1Pet pet )
        {/*TTOK*/
            String sqlstr = @"UPDATE pets SET 
                                objid             = ?1,
                                npcid             = ?2,
                                name              = ?3,
                                lvl               = ?4,
                                hp                = ?5,
                                mp                = ?6,
                                exp               = ?7,
                                lawful            = ?8 
                                WHERE item_obj_id = ?9";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = pet.get_objid();
                cmd.Parameters.Add( "?2", MySqlDbType.Int32 ).Value = pet.get_npcid();
                cmd.Parameters.Add( "?3", MySqlDbType.String ).Value = pet.get_name();
                cmd.Parameters.Add( "?4", MySqlDbType.Int32 ).Value = pet.get_level();
                cmd.Parameters.Add( "?5", MySqlDbType.Int32 ).Value = pet.get_hp();
                cmd.Parameters.Add( "?6", MySqlDbType.Int32 ).Value = pet.get_mp();
                cmd.Parameters.Add( "?7", MySqlDbType.Int32 ).Value = pet.get_exp();
                cmd.Parameters.Add( "?8", MySqlDbType.Int32 ).Value = pet.get_lawful();
                cmd.Parameters.Add( "?9", MySqlDbType.Int32 ).Value = pet.get_itemobjid();
                wrapper.ExecNonQuery( cmd );
            }
        }

        public void deletePet( int itemobjid )
        {/*TTOK*/
            String sqlstr = "DELETE FROM pets WHERE item_obj_id=?1";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = itemobjid;
                wrapper.ExecNonQuery( cmd );
            }
            _pets.Remove( itemobjid );
        }

        /// <summary>
        /// Petsテーブルに既に名前が存在するかを返す。
        /// </summary>
        /// <param name="nameCaseInsensitive">調べるペットの名前。大文字小文字の差異は無視される。</param>
        /// <returns>既に名前が存在すればtrue</returns>
        public static bool isNameExists( String nameCaseInsensitive )
        {/*TTOK*/
            String nameLower = nameCaseInsensitive.ToLower();
            String sqlstr = "SELECT item_obj_id FROM pets WHERE LOWER(name)=?1";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.String ).Value = nameLower;
                object obj = wrapper.ExecScaler( cmd );
                if ( obj == null || obj is DBNull )
                { 
                    // 同じ名前が無かった
                    return false;
                }
                if ( PetTypeTable.getInstance().isNameDefault( nameLower ) )
                { 
                    // デフォルトの名前なら重複していないとみなす
                    return false;
                }
            }
            return true;
        }

        public L1Pet getTemplate( int itemobjid )
        {/*TTOK*/
            L1Pet ret;
            _pets.TryGetValue( itemobjid, out ret );
            return ret;
        }

        public ICollection  getPetTableList()
        {/*TTOK*/
            return _pets.Values;
        }
    }
}
